﻿#pragma once

#if 1
void VdbToBin()
{
}
#else

#include "OCMain/FileUtil.h"
#include "OCMain/Log.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include "OCVolume/VolumeGridData.h"
#include <openvdb/openvdb.h>
#include <openvdb/tools/Interpolation.h>
#include "OCMain/zip/gzstream.h"

using namespace OCPP;
using namespace OCPP::Volume;

String filter = "";

void calcBox(String fileName, Vector3i& minBox, Vector3i& maxBox)
{
	openvdb::io::File file(fileName.c_str());
	if (!file.open()) {
		std::cout << "Can't open " << fileName << std::endl;
		return;
	}
	for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName(); ++nameIter) {
		std::string name = nameIter.gridName();
		if (!filter.empty() && filter != name) continue;
		openvdb::FloatGrid::Ptr grid = openvdb::gridPtrCast<openvdb::FloatGrid>(file.readGrid(name));
		openvdb::CoordBBox bbox = grid->evalActiveVoxelBoundingBox();
		openvdb::Vec3i min = bbox.min().asVec3i();
		openvdb::Vec3i max = bbox.max().asVec3i();
		minBox[0] = std::min(minBox[0], min[0]);
		minBox[1] = std::min(minBox[1], min[1]);
		minBox[2] = std::min(minBox[2], min[2]);
		maxBox[0] = std::max(maxBox[0], max[0]);
		maxBox[1] = std::max(maxBox[1], max[1]);
		maxBox[2] = std::max(maxBox[2], max[2]);
		int size[3];
		for (int i = 0; i < 3; i++)
			size[i] = (max[i] - min[i]) + 1;
		OCPP_LOG_INFO << "dimX:" << size[0] <<
			"dimY:" << size[1] <<
			"dimZ:" << size[2] <<
			"\n";

	}
}

bool conv(String fileName, String time, String output, Vector3i minBox, Vector3i maxBox, bool clipTest)
{
	openvdb::io::File file(fileName);
	if (!file.open()) {
		std::cout << "Can't open " << fileName << std::endl;
		return false;
	}

	// loop over all grids
	for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName(); ++nameIter) {

		// open the grid
		std::string name = nameIter.gridName();
		OCPP_LOG_INFO << name << "\n";
		if (!filter.empty() && filter != name) continue;

		openvdb::FloatGrid::Ptr grid = openvdb::gridPtrCast<openvdb::FloatGrid>(file.readGrid(name));
		auto isWorldSpace = grid->isInWorldSpace();

		//String value_type = grid->metaValue <std::string>("value_type");
		//if (value_type != "float") // only export float grid
		//	continue;

		// get bbox size
		openvdb::CoordBBox bbox = grid->evalActiveVoxelBoundingBox();
		openvdb::Vec3i min = bbox.min().asVec3i();
		openvdb::Vec3i max = bbox.max().asVec3i();

		int size[3];
		for (int i = 0; i < 3; i++)
			size[i] = (max[i] - min[i]) + 1;
		int dimX = size[0];
		int dimY = size[1];
		int dimZ = size[2];
		int nbVoxels = size[0] * size[1] * size[2];

		OCPP_LOG_INFO << "isWorldSpace " << (isWorldSpace ? "true" : "false") << " before dimX:" << dimX <<
			" dimY:" << dimY <<
			" dimZ:" << dimZ <<
			" nbVoxels:" << nbVoxels << "\n";

		if (clipTest && dimZ < 0.7 * maxBox[2]) return false;
		min.x() = minBox[0];
		min.y() = minBox[1];
		min.z() = minBox[2];
		max.x() = maxBox[0];
		max.y() = maxBox[1];
		max.z() = maxBox[2];

		for (int i = 0; i < 3; i++)
			size[i] = (max[i] - min[i]) + 1;
		dimX = size[0];
		dimY = size[1];
		dimZ = size[2];
		OCPP_LOG_INFO << "after dimX:" << dimX <<
			" dimY:" << dimY <<
			" dimZ:" << dimZ <<
			" nbVoxels:" << nbVoxels << "\n";

		//std::string export_name = time + "_" + nameIter.gridName() + "_" + std::to_string(size[0]) + "x" + std::to_string(size[1]) + "x" + std::to_string(size[2]) + ".raw";
		String export_name = time + "_" + nameIter.gridName() + ".raw";

		VolumeGridData gridData;
		gridData._vecFloat.resize(size[0] * size[1] * size[2]);

		int minX = min[0];
		int maxX = max[0];
		int minY = min[1];
		int maxY = max[1];
		int minZ = min[2];
		int maxZ = max[2];

		// write data
		openvdb::tools::GridSampler<openvdb::FloatGrid, openvdb::tools::BoxSampler> sampler(*grid);
		float vmin = FLT_MAX, vmax = -FLT_MAX;
		int progress = 0;
		uint32 i = 0;
		for (int z = minZ; z <= maxZ; z++) {
			for (int y = min[1]; y <= max[1]; y++) {
				for (int x = min[0]; x <= max[0]; x++, i++) {
					float v;
					//if (isWorldSpace) {
					//	v = sampler.wsSample(openvdb::Vec3R(x, y, z));
					//}
					//else {
					v = sampler.isSample(openvdb::Vec3R(x, y, z));
					//}
					gridData._vecFloat[i] = v;
					vmin = vmin < v ? vmin : v;
					vmax = vmax > v ? vmax : v;
					progress++;
				}
			}
			std::cout << "\r" << "-> " << export_name << " : " << std::setprecision(5) << float(progress) / nbVoxels * 100.f << " %        ";
		}
		std::cout << std::endl;
		std::cout << "value min/max : " << vmin << " / " << vmax << std::endl;

		auto num = dimZ * dimY * dimX;
		auto& vecChar = gridData._vecChar;
		vecChar.resize(num);
		for (uint32 i = 0; i < num; i++)
		{
			uint8 value = (gridData._vecFloat[i] - vmin) / (vmax - vmin) * 255;
			vecChar[i] = value;
		}

		ogzstream outfile(joinPath(output, export_name + ".gz").c_str());
		outfile.write((const char*)&size, sizeof(int) * 3);
		outfile.write((const char*)&vecChar[0], sizeof(uint8) * vecChar.size());
		outfile.close();

	}

	return true;
}

void VdbToBin()
{
	openvdb::initialize();
	String dir = "G:/项目/青岛/250421vdb";
	String output = "G:/项目/青岛/250421raw";

	FileUtil::makeDirectory(output);

	//filter = "density";
	//filter = "temperature";
	StringVector files = FileUtil::findFiles(U2A(dir));
	Vector3i minBox(1000), maxBox(-1000);
	for (const auto& f : files)
	{
		if (f == "." || f == "..") continue;
		//if (!StringUtil::endsWith(f, ".vdb")) continue;
		String fileName = joinPath(dir, f, "volumes","体积.001.vdb");
		calcBox(U2A(fileName), minBox, maxBox);
	}

	uint32 i = 0;
	for (const auto& f : files)
	{
		if (f == "." || f == "..") continue;
		//if (!StringUtil::endsWith(f, ".vdb")) continue;
		String fileName = joinPath(dir, f, "volumes", "体积.001.vdb");
		if (conv(U2A(fileName), std::to_string(i), U2A(output), minBox, maxBox, true))
		{
			i++;
		}
	}

	//String fileName = U2A("I:\\Data\\bunny_cloud.vdb");
	//conv(U2A(fileName), "bunny_cloud", output);

	//std::ifstream ifs(fileName, std::ios::binary);
	//if (ifs)
	//{
	//	int imageS = 64;
	//	int imageT = 64;
	//	int imageR = 64;


	//	String dateTime = "202400";
	//	VolumeGridData gridData;
	//	gridData.addDimension(dateTime);
	//	gridData.getExtent().dimX = imageS;
	//	gridData.getExtent().dimY = imageT;
	//	gridData.getExtent().dimZ = imageR;
	//	gridData.getExtent().xMin = 115.0;
	//	gridData.getExtent().xMax = 127.0;
	//	gridData.getExtent().yMin = 30.0;
	//	gridData.getExtent().yMax = 40.0;
	//	gridData.getExtent().zMax = 10000;
	//	gridData._vecChar.resize(imageS * imageT * imageR);

	//	uint32 offset = 0;
	//	for (int z = 0; z < imageR; z++)
	//	{
	//		for (int y = 0; y < imageT; y++)
	//		{
	//			for (int x = 0; x < imageS; x++, offset++)
	//			{
	//				gridData._vecChar[offset] = offset % 100;
	//			}
	//		}
	//	}

	//	StringMap globalOptions;
	//	globalOptions[VolumeOptions::Config::NameWriter] = VolumeOptions::Config::ValueD3Writer;
	//	globalOptions[VolumeOptions::Config::NameGZipCompress] = "yes";
	//	globalOptions[VolumeOptions::Config::NameMakeDirForFile] = "yes";
	//	globalOptions[VolumeOptions::Config::NameGenerateNormal] = "no";
	//	globalOptions[VolumeOptions::Config::NameOutputPath] = output;

	//	//globalOptions[VolumeOptions::Config::NameEncodeRange] = VolumeEncoder::EncodeRangeToString(VolumeEncoder::EncodeRangePercent);
	//	//globalOptions[VolumeOptions::Config::NameClipRange] = "115.0 30.0 127.0 40.0";
	//	VolumeOptions options(globalOptions);
	//	options.getWriter().write(gridData, options);
	//}
}
#endif